%{

package com.compiler.syntactic;

import com.compiler.lexico.token.Token;
import com.compiler.logger.Logger;

%}

%token IDENTIFICADOR, UINTEGER, IF, THEN, ELSE, FOR, STEP, PRINT, ARRAY, CADENA, MAYOR_IGUAL, MENOR_IGUAL, DISTINTO, ASIGNACION, NUMERO

%start programa

%%

programa: sentencias
;

sentencias: sentencia 
			| sentencias sentencia
;

sentencia: 	declaracion
			| {System.out.println("Linea #"+token.getLine()+" --> sentencia PRINT");} impresion
			| {System.out.println("Linea #"+token.getLine()+" --> sentencia IF");} seleccion 
			| {System.out.println("Linea #"+token.getLine()+" --> sentencia FOR");} bucle
			| {System.out.println("Linea #"+token.getLine()+" --> asignacion");} asignacion';'
;

declaracion: UINTEGER variables';' {System.out.println("Linea #"+token.getLine()+" --> declaracion {UINTEGER}");}
			 | ARRAY arreglo';' {System.out.println("Linea #"+token.getLine()+" --> declaracion {ARRAY}");}
			 | ARRAY ';' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> declaracion de arreglo","SINTACTICO");}
			 | ARRAY IDENTIFICADOR';' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> declaracion de arreglo","SINTACTICO");}
			 | ARRAY error';' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> declaracion de arreglo","SINTACTICO");}
			 | UINTEGER ';' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> declaracion de variable","SINTACTICO");}
			 | UINTEGER variables {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> falta ;","SINTACTICO");}
;

variables: IDENTIFICADOR 
		   | variables','IDENTIFICADOR
;

arreglo: IDENTIFICADOR '[' expresion ']'
;

seleccion: IF'('condicion')'THEN'{'sentencias'}'
		   | IF'('condicion')'THEN'{'sentencias'}' ELSE '{'sentencias'}'
		   | IF'('condicion')' '{'sentencias'}' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> falta THEN","SINTACTICO");}
		   | IF'('condicion')'THEN {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> falta {SENTENCIAS}","SINTACTICO");}
		   | IF'('error')' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> IF mal formddado","SINTACTICO");} sentencias'}'
		   | IF'('error')'THEN '{'{Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> IF mal formado","SINTACTICO");} sentencias'}' error
;

condicion: condicion comparador expresion
			| expresion comparador expresion
;

bucle: FOR'('asignacion';'condicion';'STEP IDENTIFICADOR')' '{'sentencias'}'
	   | FOR'('asignacion';'condicion';' error ')' '{'sentencias'}' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" -->  FOR mal formado","SINTACTICO");}
	   | FOR'('asignacion ';' error ';' error ')' '{'sentencias'}' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> FOR mal formado","SINTACTICO");}
	   | FOR'(' error ';' error ';' error ')' '{'sentencias'}' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> FOR mal formado","SINTACTICO");}
	   | FOR'(' error ';' error ';' error ')' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> FOR mal formado, falta bloque {}","SINTACTICO");}
	   | FOR error {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" -->  FOR mal formado","SINTACTICO");}
;

impresion: PRINT'('CADENA')'';'
		   | PRINT'('argumento')'';'
		   | PRINT CADENA ';' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> faltan parentesis","SINTACTICO");}
		   | PRINT'('CADENA')' {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> faltan ;","SINTACTICO");}
		   | PRINT error {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> PRINT mal formado ","SINTACTICO");}
		   
;

asignacion: IDENTIFICADOR ASIGNACION expresion 
			| IDENTIFICADOR '[' expresion ']' ASIGNACION expresion
			| IDENTIFICADOR error {Logger.getInstance().log("SINTACTICO", Logger.ERRORLevel,"Linea #"+token.getLine()+" --> asignacion incompleta, falta constante","SINTACTICO");}
;

comparador: '<' 
			| '>' 
			| '=' 
			| MENOR_IGUAL 
			| MAYOR_IGUAL
;

expresion: expresion '+' termino {}
		   | expresion '-' termino 
		   | termino
;

termino: termino '*' argumento 
		 | termino '/' argumento 
		 | argumento
;

argumento: IDENTIFICADOR 
		   | IDENTIFICADOR '[' expresion ']'

;

%%
private com.compiler.logger.TokenPipe tokenPipe;
private Token token;

public Parser(com.compiler.logger.TokenPipe tokenPipe) {
	this.tokenPipe = tokenPipe;
}

private int yylex(){
	int yyl_return = -1;
	while (!this.tokenPipe.isEmpty()) {
		token = this.tokenPipe.getToken();
		yyl_return = token.yylex();
		yylval = token.getParserVal();
		return yyl_return;
	}
	return 0;
}

private void yyerror(String stack_underflow_aborting) {
}
